package dao

import (
	"context"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"

	"goldtree/internal/entity"
)

// UserDao 用户数据访问对象
type UserDao struct{}

var User = UserDao{}

// Insert 创建用户
func (dao *UserDao) Insert(ctx context.Context, user *entity.User) (int64, error) {
	// 排除ID字段，避免自增字段冲突
	data := g.Map{
		"username":      user.Username,
		"password":      user.Password,
		"email":         user.Email,
		"phone":         user.Phone,
		"nickname":      user.Nickname,
		"avatar":        user.Avatar,
		"role":          user.Role,
		"status":        user.Status,
		"last_login_at": user.LastLoginAt,
		"last_login_ip": user.LastLoginIp,
		"login_count":   user.LoginCount,
		"created_at":    user.CreatedAt,
		"updated_at":    user.UpdatedAt,
	}

	result, err := g.DB().Model("users").Ctx(ctx).Data(data).Insert()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

// Update 更新用户
func (dao *UserDao) Update(ctx context.Context, id int, user *entity.User) error {
	user.UpdatedAt = gtime.Now()
	_, err := g.DB().Model("users").Ctx(ctx).Where("id", id).Data(user).Update()
	return err
}

// Delete 删除用户
func (dao *UserDao) Delete(ctx context.Context, id int) error {
	_, err := g.DB().Model("users").Ctx(ctx).Where("id", id).Delete()
	return err
}

// GetById 根据ID获取用户
func (dao *UserDao) GetById(ctx context.Context, id int) (*entity.User, error) {
	var user *entity.User
	err := g.DB().Model("users").Ctx(ctx).Where("id", id).Scan(&user)
	if err != nil {
		return nil, err
	}
	return user, nil
}

// GetByUsername 根据用户名获取用户
func (dao *UserDao) GetByUsername(ctx context.Context, username string) (*entity.User, error) {
	var user *entity.User
	err := g.DB().Model("users").Ctx(ctx).Where("username", username).Scan(&user)
	if err != nil {
		return nil, err
	}
	return user, nil
}

// GetByEmail 根据邮箱获取用户
func (dao *UserDao) GetByEmail(ctx context.Context, email string) (*entity.User, error) {
	var user *entity.User
	err := g.DB().Model("users").Ctx(ctx).Where("email", email).Scan(&user)
	if err != nil {
		return nil, err
	}
	return user, nil
}

// GetList 获取用户列表
func (dao *UserDao) GetList(ctx context.Context, page, limit int, conditions ...interface{}) ([]*entity.User, error) {
	model := g.DB().Model("users").Ctx(ctx)

	// 添加查询条件
	if len(conditions) > 0 {
		model = model.Where(conditions[0], conditions[1:]...)
	}

	var users []*entity.User
	err := model.Order("created_at DESC").Limit((page-1)*limit, limit).Scan(&users)
	if err != nil {
		return nil, err
	}
	return users, nil
}

// GetCount 获取用户总数
func (dao *UserDao) GetCount(ctx context.Context, conditions ...interface{}) (int, error) {
	model := g.DB().Model("users").Ctx(ctx)

	// 添加查询条件
	if len(conditions) > 0 {
		model = model.Where(conditions[0], conditions[1:]...)
	}

	count, err := model.Count()
	if err != nil {
		return 0, err
	}
	return count, nil
}

// IsUsernameExists 检查用户名是否存在
func (dao *UserDao) IsUsernameExists(ctx context.Context, username string) (bool, error) {
	count, err := g.DB().Model("users").Ctx(ctx).Where("username", username).Count()
	if err != nil {
		return false, err
	}
	return count > 0, nil
}

// IsEmailExists 检查邮箱是否存在
func (dao *UserDao) IsEmailExists(ctx context.Context, email string) (bool, error) {
	count, err := g.DB().Model("users").Ctx(ctx).Where("email", email).Count()
	if err != nil {
		return false, err
	}
	return count > 0, nil
}

// UpdateLoginInfo 更新登录信息
func (dao *UserDao) UpdateLoginInfo(ctx context.Context, id int, ip string) error {
	data := g.Map{
		"last_login_at": gtime.Now(),
		"last_login_ip": ip,
		"login_count":   g.DB().Raw("login_count + 1"),
		"updated_at":    gtime.Now(),
	}
	_, err := g.DB().Model("users").Ctx(ctx).Where("id", id).Data(data).Update()
	return err
}

// UpdateStatus 更新用户状态
func (dao *UserDao) UpdateStatus(ctx context.Context, id int, status string) error {
	data := g.Map{
		"status":     status,
		"updated_at": gtime.Now(),
	}
	_, err := g.DB().Model("users").Ctx(ctx).Where("id", id).Data(data).Update()
	return err
}

// UserTokenDao 用户令牌数据访问对象
type UserTokenDao struct{}

var UserToken = UserTokenDao{}

// Insert 创建令牌
func (dao *UserTokenDao) Insert(ctx context.Context, token *entity.UserToken) (int64, error) {
	// 排除ID字段，避免自增字段冲突
	data := g.Map{
		"user_id":    token.UserId,
		"token":      token.Token,
		"token_type": token.TokenType,
		"expires_at": token.ExpiresAt,
		"is_revoked": token.IsRevoked,
		"created_at": token.CreatedAt,
	}

	result, err := g.DB().Model("user_tokens").Ctx(ctx).Data(data).Insert()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

// GetByToken 根据令牌获取记录
func (dao *UserTokenDao) GetByToken(ctx context.Context, token string) (*entity.UserToken, error) {
	var userToken *entity.UserToken
	err := g.DB().Model("user_tokens").Ctx(ctx).Where("token", token).Where("is_revoked", false).Scan(&userToken)
	if err != nil {
		return nil, err
	}
	return userToken, nil
}

// GetByUserId 根据用户ID获取令牌列表
func (dao *UserTokenDao) GetByUserId(ctx context.Context, userId int, tokenType string) ([]*entity.UserToken, error) {
	model := g.DB().Model("user_tokens").Ctx(ctx).Where("user_id", userId).Where("is_revoked", false)

	if tokenType != "" {
		model = model.Where("token_type", tokenType)
	}

	var tokens []*entity.UserToken
	err := model.Order("created_at DESC").Scan(&tokens)
	if err != nil {
		return nil, err
	}
	return tokens, nil
}

// RevokeToken 撤销令牌
func (dao *UserTokenDao) RevokeToken(ctx context.Context, token string) error {
	data := g.Map{"is_revoked": true}
	_, err := g.DB().Model("user_tokens").Ctx(ctx).Where("token", token).Data(data).Update()
	return err
}

// RevokeUserTokens 撤销用户的所有令牌
func (dao *UserTokenDao) RevokeUserTokens(ctx context.Context, userId int, tokenType string) error {
	model := g.DB().Model("user_tokens").Ctx(ctx).Where("user_id", userId)

	if tokenType != "" {
		model = model.Where("token_type", tokenType)
	}

	data := g.Map{"is_revoked": true}
	_, err := model.Data(data).Update()
	return err
}

// CleanExpiredTokens 清理过期令牌
func (dao *UserTokenDao) CleanExpiredTokens(ctx context.Context) error {
	_, err := g.DB().Model("user_tokens").Ctx(ctx).Where("expires_at < ?", gtime.Now()).Delete()
	return err
}

// IsTokenValid 检查令牌是否有效
func (dao *UserTokenDao) IsTokenValid(ctx context.Context, token string) (bool, error) {
	count, err := g.DB().Model("user_tokens").Ctx(ctx).
		Where("token", token).
		Where("is_revoked", false).
		Where("expires_at > ?", gtime.Now()).
		Count()
	if err != nil {
		return false, err
	}
	return count > 0, nil
}
